package com.shoping.web.component.processor;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

/**
 * BeanPostProcess接口只在 test 的初始化阶段进行扩展（注入 spring 上下文前后），
 * 而InstantiationAwareBeanPostProcessor接口在此基础上增加了 3 个方法，
 * 把可扩展的范围增加了实例化阶段和属性注入阶段。
 * <p>
 * 使用场景：这个扩展点非常有用 ，无论是写中间件和业务中，都能利用这个特性。
 * 比如对实现了某一类接口的 test 在各个生命期间进行收集，或者对某个类型的 test 进行统一的设值等等。
 */
@Slf4j
@Configuration
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

    /**
     * 实例化 test 之前，相当于 new 这个 test 之前
     *
     * @param beanClass
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
        if (beanClass == RestTemplate.class) {
            log.info("-----测试1【初始化方法之前】.postProcessBeforeInstantiation===" + beanClass.getSimpleName());
        }
        return null;
    }

    /**
     * 实例化 test 之后，相当于 new 这个 test 之后
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        if (bean instanceof RestTemplate) {
            log.info("-----测试2【初始化方法之后】.postProcessAfterInstantiation===" + bean.getClass().getSimpleName());
        }
        return true;
    }

    /**
     * test 已经实例化完成，在属性注入时阶段触发，@Autowired,@Resource等注解原理基于此方法实现
     *
     * @param pvs
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
        if (bean instanceof RestTemplate) {
            log.info("-----测试3【属性填充时】测试BeanPostProcessor.postProcessProperties===" + bean.getClass().getSimpleName());
        }
        return pvs;
    }

    /**
     * 初始化 test 之前，相当于把 test 注入 spring 上下文之前
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof RestTemplate) {
            log.info("-----测试4【对象注入容器前】.postProcessBeforeInitialization===" + bean.getClass().getSimpleName());
        }
        return bean;
    }

    /**
     * 初始化 test 之后，相当于把 test 注入 spring 上下文之后
     *
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        if (bean instanceof RestTemplate) {
            log.info("-----测试5【对象注入容器后】.postProcessAfterInitialization===" + bean.getClass().getSimpleName());
        }
        return bean;
    }
}
